GCP metadata server から spreadsheet などの API 叩けるか
叩ける
spreadsheet にアクセスできる scope が必要
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/spreadsheets.readonly
など
GCP 内
サービスアカウントキーなくてもアタッチされたサービスアカウントに共有すれば叩ける
ローカル(Application Default Credential)
gcloud auth application-default login 時に scope を指定する
---.icon
以下調査やコードリーディング
$ gcloud auth print-access-token
スコープ設定できない
やってない
Matadata Server に scope 付けてリクエストしたら取れる説
Workload Identity を有効にしたクラスタ & サービスアカウントを用意する
GSA のメールアドレスに spreadsheet を共有する
$ kubectl run -it --rm gcloud-slim --image=google/cloud-sdk:slim --restart=Never --serviceaccount={KSA} -- bash
gcloud じゃなくていいけど
$ curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token?scopes=https%3A//www.googleapis.com/auth/spreadsheets.readonly
OAuth2 Access Token
プロジェクトの Spreadsheet API が有効でないといけない
とれる!!
scope を省略する(=cloud-platform) だと取れない
code:err
{
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT",
"domain": "googleapis.com",
"metadata": {
"service": "sheets.googleapis.com",
"method": "google.apps.sheets.v4.SpreadsheetsService.GetSpreadsheet"
}
}
]
}
}
クライアントライブラリでやるには?
code:index.js
pu
普通に Workload Identity が有効な gke 上でこれ実行したらシート読めた
google-auth-library がよしなに metadata server 叩いているんだろう
ローカルで gcloud auth login & gcloud auth application-default loginしていても通らないなあ
Gaxios のエラーメッセージの Token で tokeinfo を叩く
curl -H 'Authorization: Bearer {TOKEN}' https://oauth2.googleapis.com/tokeinfo
code:tokeinfo
...
spreadsheet がない
コードリーディングの結果、WellKnownFile が OAuth2 Client Secret の場合は GoogleAuth に渡した scope が設定されない(まあそうか)
Client Secret を生成する際に scope を設定するといける
$ gcloud auth application-default login --scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/spreadsheets.readonly
デフォルトの userinfo.email や accounts.reauth がないと expire して困る?
ttl 程度待ってみる
1日経っても叩ける
これで生成した application_default_credentials.json が置かれていたらおもむろに spreadsheet api を叩ける!!
Cloud Functions でも確認
取れた
Compute Engine のインスタンスに scope を設定していたら metadata server がリクエスト時の scope パラメータを無視するという話
あるらしいが手元で確認はしてない
---.icon
const sheets = google.sheets({version: 'v4', auth: authClient }); ← これ追う
google.auth の実体
google.sheets(...)
引数は sheets_v4.Options
GlobalOptions
googleapis-common のこれ、auth のみ
auth?: GoogleAuth | OAuth2Client | BaseExternalAccountClient | string;
返り値は Sheets
sheets.spreadsheets.values
spreadsheets は Resource$Spreadsheets
spreadsheets.values も同様に Resource$Spreadsheets$Values
リソースの階層は $ 区切り
context: APIRequestContext を受け渡す
GlobalOptions を持ってる、google も GlobalOptions
get(...)
parameters の context
createAPIRequest を呼ぶ
createAPIReqeust
parameters: APIRequestParams に一通りの値が入って呼ばれる
例
options.url, options.method, API のリクエスト先情報
params.spreadsheetId, params.range, API のパラメータ
requiredParams, pathParams, パラメータバリデーションに使う?
context
params.auth, options.auth の順に authClient として束縛
authClient が文字列なら API Key として使う(params.key にセットする)
options.http2 でなければ OAuth2Client を仮定してリクエスト
authClient.request(options)
authClient.request
中で getClient している
つまり auth(new google.auth.GoogleAuth したインスタンス)を渡しても、auth.getClient() した結果どちらを渡しても良い?
ダメそうに思えるけどどちらも request メソッドが共通
GoogleAuth を渡していたら client を呼んで request する
auth : GoogleAuth#request → GoogleAuth#getClient → client.request
authClient: client.request
getClient
GKE 上だと Compute
ローカルでなんも指定しないと UserRefreshClient
cachedCredentials > keyFilename(サービスアカウントキー) > getApplicationDefaultAsync
getApplicationDefaultAsync
EnvironmentVariable > WellKnownFile > Compute
Compute 以外は Client が JWT, BaseExternalAccountClient の場合に scope が設定される
ローカルでなんも指定しない OAuth2 Client Secret の場合(UserRefreshClient)は設定されない
BaseExternalAccountClient
External = AWS, GCE, OIDC-based providers
仮にコードを書き換えて scope 設定したらどうなる?
RefreshClient に scope 設定する余地ない
getClient したものって結局何
credentials の request メソッドはどこからくる
UserRefreshClient は OAuth2Client
JWTClient は OAuth2Client, IdTokenProvider
BaseExternalAccountClient は自前で実装
fromStreamAsync, stream でファイル読む参考実装として
OAuth2Client#request
getRequestMetadataAsync
UserRefreshClient は OAuth2Client の実装を使う
JWTClient は override していてここで JWT からトークン取ってくるのだろう
リクエスト投げるところでどう Authorization ヘッダを作っている?
impersonate はどこで考慮されている?
cachedClient にImpersonated 型がある
CLOUDSDK_AUTH_IMPERSONATE_SERVICE_ACCOUNT → 使えない
名前的にも CLOUDSDK 用か
オプションや環境変数からいい感じにディスカバリしてくれる仕組みはなくて、自分で Impersonated なクライアントインスタンスを作って渡す
const {Impersonated} = require('google-auth-library'); を使って認証する
クライアントライブラリの auth に { getClient: () => Impersonated } なオブジェクトを渡す
まだ限定的な対応、Spreadsheet で使うには token 取ってきて明に渡せば良い?
---.icon
---.icon
~/.config/gcloud/application_default_credentials.json は OAuth2 Client Secret
GOOGLE_APPLICATION_CREDENTIALS とは違う
code:spreadsheet.js